﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.ComponentModel;
using System.Reflection;
using System.Collections.Specialized;
using System.Net;
using System.Web;
using ConferenceRoomSchedule.ExchangeInteface;

namespace ConferenceRoomSchedule
{
    public class ExchangeProvider
    {

        public string UserName { get; set; }

        public string Password { get; set; }

        public string Domain { get; set; }

        public string EmailAddress { get; set; }

        public string ServiceURL { get; set; }

        public bool Success { get; set; }
        public string StatusMessage { get; set; }

        public void Initialize(string name, NameValueCollection config)
        {

            //  base.Initialize(name, config);
            UserName = "*****";//config["username"];
            Password = "******"; //config["password"];
            Domain = "******";// config["domain"];
            EmailAddress = "******";// config["emailaddress"];
            ServiceURL = "******";// config["serviceurl"];
            //ObjectDumper.Write(this);
        }

        public IEnumerable<AppointmentData> RetrieveCalendars(string CalendardAccount)
        {
            List<AppointmentData> data;
            NetworkCredential NetCreds;
            DataTable table;
            data = new List<AppointmentData>();

            if (Domain != "")
                NetCreds = new NetworkCredential(UserName, Password, Domain);
            else
                NetCreds = new NetworkCredential(UserName, Password);

            using (ExchangeServiceBinding binding = new ExchangeServiceBinding { Url = ServiceURL, Credentials = NetCreds })
            {


                data.AddRange(GetOtherUsersData(CalendardAccount, binding));
                return data;


            }

				
			// Identifies the maximum number of redirections through either SCP pointer or Autodiscover redirects.
			int maxHops = 10;

			// Call Autodiscover service.
			Autodiscover.AutodiscoverResponseXml response =
				Autodiscover.Discover(
					CalendardAccount,
					NetCreds,
					ref maxHops,
					false);

           


               
                
            
            return data;
        }

        private IEnumerable<AppointmentData> GetDefaultUserData(string source, ExchangeServiceBinding binding)
        {
            FindItemType findItemRequest = new FindItemType
            {
                ItemShape =
                    new ItemResponseShapeType { BaseShape = DefaultShapeNamesType.AllProperties }
            };
            //TODO: Need an actual range passed in...
            findItemRequest.Item = new CalendarViewType
            {
                StartDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1),
                EndDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddMonths(1).AddDays(0)
            };

            // FindItem also takes a traversal value - Shallow is fine
            findItemRequest.Traversal = ItemQueryTraversalType.Shallow;

            DistinguishedFolderIdType myCalendarFolder = new DistinguishedFolderIdType { Id = DistinguishedFolderIdNameType.calendar };
            findItemRequest.ParentFolderIds = new BaseFolderIdType[] { myCalendarFolder };


            // Finally submit the FindItem request to the server
            FindItemResponseType response = binding.FindItem(findItemRequest);

            //If everything went well, you get a set of mesages as response
            //List<AppointmentData> scheduleContent = new List<AppointmentData>();
            List<AppointmentData> returnlist = new List<AppointmentData>();
            foreach (FindItemResponseMessageType firmt in response.ResponseMessages.Items)
            {


                /////+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                /////
                //if (firmt.ResponseClass == ResponseClassType.Success)
                //{

                //    ArrayOfRealItemsType mailboxItems = (ArrayOfRealItemsType)firmt.RootFolder.Item;

                //    for (int itemCount = 0; itemCount < mailboxItems.Items.Length; itemCount++)
                //    {
                //        ItemType inboxItem = mailboxItems.Items[itemCount];

                //        // Call GetItem on each ItemId to retrieve the
                //        // item’s Body property and any AttachmentIds.

                //        //

                //        // Form the GetItem request.

                //        GetItemType getItemRequest = new GetItemType();
                //        getItemRequest.ItemShape = new ItemResponseShapeType();

                //        // AllProperties on a GetItem request WILL return
                //        // the message body.

                //        getItemRequest.ItemShape.BaseShape = DefaultShapeNamesType.AllProperties;

                //        getItemRequest.ItemIds = new ItemIdType[1];
                //        getItemRequest.ItemIds[0] = (BaseItemIdType)inboxItem.ItemId;

                //        GetItemResponseType getItemResponse = binding.GetItem(getItemRequest);

                //        // We only passed in one ItemId to the GetItem
                //        // request. Therefore, we can assume that
                //        // we got at most one Item back.
                //        ItemInfoResponseMessageType getItemResponseMessage = getItemResponse.ResponseMessages.Items[0] as ItemInfoResponseMessageType;

                //        if (getItemResponseMessage != null)
                //        {
                //            if (getItemResponseMessage.ResponseClass == ResponseClassType.Success
                //                && getItemResponseMessage.Items.Items != null
                //                && getItemResponseMessage.Items.Items.Length > 0)
                //            {
                //                inboxItem = getItemResponseMessage.Items.Items[0];
                //            }

                //            else
                //            {

                //              //  return;
                //            }

                //        }

                //        else
                //        {
                //            //return;
                //        }

                //        // Now the message Body is there.

                //        BodyType messageBody = inboxItem.Body;


                //    }
                //}




                //////++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                //if first folder has any results. - but we only specified one folder. Anyhow ...
                if (firmt.RootFolder != null && firmt.RootFolder.TotalItemsInView > 0)
                {
                    foreach (CalendarItemType it in ((ArrayOfRealItemsType)firmt.RootFolder.Item).Items)
                    {
                        string s;

                        if (it.Subject == "Demo Meeting")
                            s = "";

                        returnlist.Add(new AppointmentData(source)
                        {

                            Category = it.Categories,
                            Subject = it.Subject,
                            Location = it.Location,
                            MeetingStartTime = it.Start.ToLocalTime(),
                            MeetingEndTime = it.End.ToLocalTime(),
                            Duration = it.Duration,
                            Sensitivity = it.Sensitivity.ToString(),
                            Source = "DEFAULT",
                            Attendees = GetAttendee(it.DisplayTo),
                            Body = ""
                        });
                    }
                }
            }
            return returnlist;
        }

        private string[] GetAttendee(string Attendees)
        {
            char[] delimiter = { ';' };
            if (Attendees != null)
                return Attendees.Split(delimiter, StringSplitOptions.RemoveEmptyEntries);
            else
                return null;
        }

        private IEnumerable<AppointmentData> GetOtherUsersData(string source, ExchangeServiceBinding binding)
        {
            FindItemType findItemRequest = new FindItemType
            {
                ItemShape =
                    new ItemResponseShapeType { BaseShape = DefaultShapeNamesType.AllProperties }
            };
            //TODO: Need an actual range passed in...
            findItemRequest.Item = new CalendarViewType
            {
                StartDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1),
                EndDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddMonths(1).AddDays(-1)
            };

            // FindItem also takes a traversal value - Shallow is fine
            findItemRequest.Traversal = ItemQueryTraversalType.Shallow;

            //// ...for someone else's calendar folder to which you have permissions
            DistinguishedFolderIdType otherUsersCalendarFolder = new DistinguishedFolderIdType { Id = DistinguishedFolderIdNameType.calendar };
            // You specify which user using an e-mail address
            EmailAddressType email = new EmailAddressType();
            //TODO: check for null.
            email.EmailAddress = source ;// source.values.Find(x => x.Key == "email").Value;
            otherUsersCalendarFolder.Mailbox = email;
            findItemRequest.ParentFolderIds = new BaseFolderIdType[] { otherUsersCalendarFolder };

            // Finally submit the FindItem request to the server
            FindItemResponseType response = binding.FindItem(findItemRequest);

            //If everything went well, you get a set of mesages as response
            List<AppointmentData> returnlist = new List<AppointmentData>();

            foreach (FindItemResponseMessageType firmt in response.ResponseMessages.Items)
            {
                //if first folder has any results. - but we only specified one folder. Anyhow ...

                if (firmt.RootFolder != null && firmt.RootFolder.TotalItemsInView > 0)
                {
                    int localID = 0;
                    foreach (CalendarItemType it in ((ArrayOfRealItemsType)firmt.RootFolder.Item).Items)
                    {
                        
                        returnlist.Add(new AppointmentData("")
                        {
                            ID = localID.ToString(),
                            Alias = email.EmailAddress,
                            Category = it.Categories,
                            Subject = it.Subject,
                            Location = it.Location,
                            Source = email.EmailAddress,
                            MeetingStartTime = it.Start.ToLocalTime(),
                            MeetingEndTime = it.End.ToLocalTime(),
                            Attendees = GetAttendee(it.DisplayTo),
                            Duration = it.Duration

                        });

                        localID++;
                    }
                }
            }
            return returnlist;
        }


      
    }

    public class AppointmentData
    {
        public AppointmentData(string source)
        {
            Source = source;
        }
        public string ID { get; set; }
        public string Resource { get; set; }
        public string Subject { get; set; }
        public string Location { get; set; }
        public string[] Category { get; set; }
        public string Body { get; set; }
        public DateTime MeetingStartTime { get; set; }
        public DateTime MeetingEndTime { get; set; }
        public string Duration { get; set; }
        public string Source { get; set; }
        public string Sensitivity { get; set; }
        public string Alias { get; set; }
        public string[] Attendees { get; set; }
        public override string ToString()
        {
            if (Category != null && Category.Length > 0)
                return Category[0];
            else
                return "";
        }
    }

    //FROM: http://blog.lozanotek.com/archive/2007/05/09/Converting_Custom_Collections_To_and_From_DataTable.aspx
    public class CollectionHelper
    {
        private CollectionHelper()
        {
        }

        public static DataTable ConvertTo<T>(IList<T> list)
        {
            DataTable table = CreateTable<T>();
            Type entityType = typeof(T);
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(entityType);

            foreach (T item in list)
            {
                DataRow row = table.NewRow();

                foreach (PropertyDescriptor prop in properties)
                {
                    row[prop.Name] = prop.GetValue(item);
                }

                table.Rows.Add(row);
            }

            return table;
        }

        public static IList<T> ConvertTo<T>(IList<DataRow> rows)
        {
            IList<T> list = null;

            if (rows != null)
            {
                list = new List<T>();

                foreach (DataRow row in rows)
                {
                    T item = CreateItem<T>(row);
                    list.Add(item);
                }
            }

            return list;
        }

        public static IList<T> ConvertTo<T>(DataTable table)
        {
            if (table == null)
            {
                return null;
            }

            List<DataRow> rows = new List<DataRow>();

            foreach (DataRow row in table.Rows)
            {
                rows.Add(row);
            }

            return ConvertTo<T>(rows);
        }

        public static T CreateItem<T>(DataRow row)
        {
            T obj = default(T);
            if (row != null)
            {
                obj = Activator.CreateInstance<T>();

                foreach (DataColumn column in row.Table.Columns)
                {
                    PropertyInfo prop = obj.GetType().GetProperty(column.ColumnName);
                    try
                    {
                        object value = row[column.ColumnName];
                        prop.SetValue(obj, value, null);
                    }
                    catch
                    {
                        // You can log something here
                        throw;
                    }
                }
            }

            return obj;
        }

        public static DataTable CreateTable<T>()
        {
            Type entityType = typeof(T);
            DataTable table = new DataTable(entityType.Name);
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(entityType);

            foreach (PropertyDescriptor prop in properties)
            {
                table.Columns.Add(prop.Name, prop.PropertyType);
            }

            return table;
        }
    }

}
